/**
 * @name weathermap
 * @author Sowmya Balasubramanian, Aaron Hong, Evangelos Chaniotakis,
 *         David Robertson
 */

// only global besides icons
var wm;

function WMParams() {
    this.weathermap = new WeathermapParams();
    this.renderer = new RendererParams();
    this.topology = new TopologyParams();
    this.metrics = new MetricParams();
    this.path = new PathParams();
}

function WeathermapParams() {
    this.layoutType = "geo";
    this.auto = 1;
    this.lod = 0;
    this.showSdn = true;
    this.showIp = true;
    this.showSites = true;
    this.showPeers = false;
    this.peersOnly = false;
    this.saveShowSdn = this.showSdn;
    this.saveShowIp = this.showIp;
    this.saveShowPeers = this.showPeers;
    this.saveShowSites = this.showSites;
    this.pathChoice = undefined;
    this.metricChoice = 2;
    this.metricTypeChoice = 0;
    this.lvVal=0;
    this.demoMode = "";
    this.flash = false;
    this.eventDummy = new Object();
    // initialize sliders
    this.resSlider = new Slider(document.getElementById("resSlider"), document.getElementById("resSliderInput"));
    this.resPeriods = {
        "seconds": {"start": 30, "end": 3600},
        "minutes": {"start": 60, "end": 1440},
        "hours": {"start": 24, "end": 368},
        "days": {"start": 7, "end": 365}
    }
    console.log(this.resPeriods["minutes"].start);
    this.currentPeriod = "minutes";
    this.aggrSlider = new Slider(document.getElementById("aggrSlider"), document.getElementById("aggrSliderInput"));
}

/**
 * Set the location of the servlet URL.
 * Default is the empty string "" and therefore uses a relative URL,
 * essentially the root directory of the URL.
 */
var servletUrl = "";

/**
 * This function is executed when the page is first loaded. The map is
 * initialized to a default center and zoom level and other initial
 * settings are made. It gets the data and sets up the event listeners,
 * along with metric polling.
 */
function initialize() {
    wm = new WMParams();
    wm.weathermap.flash=false;
    checkForDebug();
    if (GBrowserIsCompatible()) {
        initializeRender(gup("demo"));

        GEvent.addListener(wm.weathermap.eventDummy, "lodChanged", function() {
            console.log("changed lod");
            clearOverlays();
            setMapBG(wm.weathermap.lvVal);
            prepareNodesForMap();
            prepareLinksForMap();
            makePath();
            drawNodes();
            drawLinks();
            drawPath();
            drawCopyrightInfo();
        });

        GEvent.addListener(wm.weathermap.eventDummy, "topologyChanged", function() {
            console.log("changed topo");
            clearOverlays();
            setMapBG(wm.weathermap.lvVal);
            prepareNodesForMap();
            prepareLinksForMap();
            makePath();
            drawNodes();
            drawLinks();
            drawPath();
            drawCopyrightInfo();
        });

        GEvent.addListener(wm.weathermap.eventDummy, "metricsChanged", function() {
            console.log("new metrics data");
            updateLinks();
        });

        GEvent.addListener(wm.weathermap.eventDummy, "pathsChanged", function() {
            console.log("changed paths");

            // Update the sidebar with new path data
            // But don't automatically update it
            updateOscarsForm();
        });

        GEvent.addListener(wm.weathermap.eventDummy, "showPath", function(){
            makePath();
            drawPath();
        });

        GEvent.addListener(wm.weathermap.eventDummy, "showMetric", function() {
             chooseUtilizationLegend();
             getMetrics();
        });

        commonInitialize();
        wm.weathermap.pathChoice = "none";

        // get topology and metrics
        getTopology(wm.weathermap.layoutType);
        getMetrics();
        getPaths();
        setTimeout("getMetrics()", 30000);
        // update reservations every 10 minutes
        setInterval("getPaths()", 600000);
    }
}

//Initialize function for Flex

function initializeFlex() {
    wm = new WMParams();
    wm.weathermap.flash = true;
    checkForDebug();
    commonInitialize();

    // Flex listeners
    GEvent.addListener(wm.weathermap.eventDummy, "topologyChanged", function() {
        console.log("changed topo");
        clearOverlays();
        setMapBG(wm.weathermap.lvVal);
        prepareNodesForMap();
        prepareLinksForMap();
        drawNodes();
        drawLinks();
    });

    GEvent.addListener(wm.weathermap.eventDummy, "lodChanged", function() {
            console.log("changed lod");
            clearOverlays();
            setMapBG(wm.weathermap.lvVal);
            prepareNodesForMap();
            prepareLinksForMap();
            //makePath();
            drawNodes();
            drawLinks();
            //drawPath();
            //drawExtra();
        });

    GEvent.addListener(wm.weathermap.eventDummy, "pathsChanged", function() {
            console.log("changed paths");

            // Update the sidebar with new path data
            // But don't automatically update it
            updateOscarsForm();
        });

    GEvent.addListener(wm.weathermap.eventDummy, "showPath", function() {
            makePath();
            drawPath();
        });


    GEvent.addListener(wm.weathermap.eventDummy, "metricsChanged", function() {
            console.log("new metrics data");
            updateLinks();
        });

     GEvent.addListener(wm.weathermap.eventDummy, "showMetric", function() {
             chooseUtilizationLegend();
             getMetrics();
        });

    // This is to give the flash map sometime to load
    setTimeout("initializeFlexHelper()", 2000);
}

function initializeFlexHelper() {
    getTopology(wm.weathermap.layoutType);
    getMetrics();
    getPaths();
    setTimeout("getMetrics()", 30000);
    // update reservations every minute
    setInterval("getPaths()", 60000);
    getFlexApp('weathermap').setDemo(gup("demo"));
}

// This function returns the appropriate reference,
// depending on the browser.
function getFlexApp(appName) {
    if (navigator.appName.indexOf ("Microsoft") !=-1) {
        return window[appName];
    } else {
        if (document.embeds[appName] != null) {
            // Safari
            return document.embeds[appName];
        } else {
            // Firefox
            return document[appName];
        }
    }
}

//needed for triggering from flex
function triggerLODChange(lodfromflex) {
    wm.weathermap.lod = lodfromflex;
    GEvent.trigger(wm.weathermap.eventDummy,"lodChanged");
}

/**
 * Material common to both Javascript and Flex initialization
 */

// Gracefully ignore debugging commands.
function checkForDebug() {
    if (! ("console" in window) || !("firebug" in console)) {
        var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group"
        , "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
        window.console = {};
        var EmptyFn = function() {};
        for (var i = 0; i <names.length; ++i) window.console[names[i]] = EmptyFn;
    } else {
        // only has a purpose in Flex
        var triggerFirebugConsole = window.console;
    }
}

function commonInitialize() {
    // set resize handler
    window.onresize = rendererResize;
    // all these are globals

    // Reset some document stuff
    document.getElementById("form").reset();
    // initialize option controls
    document.getElementById("labelsCheckbox").checked = true;
    document.getElementById("lvCheckbox").checked = false;
    document.getElementById("sdnCheckbox").checked = true;
    document.getElementById("ipCheckbox").checked = true;
    document.getElementById("sitesCheckbox").checked = true;
    document.getElementById("peersCheckbox").checked = false;
    document.getElementById("peersOnlyCheckbox").checked = false; 
    document.getElementById("altmap_canvas").style.display='none';
    // tooltip sometimes doesn't display correctly at first otherwise
    var toggle = document.getElementById("sidebarViewToggle");
    toggle.title = "Hide sidebar";
    var optionToggle = document.getElementById("optionToggle");
    optionToggle.title = "Hide control options";
    var percentToggle = document.getElementById("percentToggle");
    percentToggle.title = "Hide utilization legend";
    var mbpsToggle = document.getElementById("mbpsToggle");
    mbpsToggle.title = "Hide utilization legend";
    var markerToggle = document.getElementById("markerToggle");
    markerToggle.title = "Hide marker legend";
    initResolutionSlider();
    initAggregationSlider();
    wm.weathermap.demoMode = gup("demo");
    if (wm.weathermap.demoMode == "globe") {
        togglePeersOnly(true);
        toggleFullScreen(true);
    }
}

// gets parameter from URL
// from http://www.netlobo.com/url_query_string_javascript.html
function gup(name) {
    name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp( regexS );
    var results = regex.exec( window.location.href );
    if (results == null) {
        return "";
    } else {
        return results[1];
    }
}

function initResolutionSlider() {
    wm.weathermap.resSlider.setMinimum(1);
    wm.weathermap.resSlider.setMaximum(30);
    wm.weathermap.resSlider.mouseUpHandler = resSliderMouseUp;
    wm.weathermap.resSlider.onchange = function () {
	      document.getElementById("resValue").value =
            wm.weathermap.resSlider.getValue();
    };
    var resValue = document.getElementById("resValue");
    resValue.onchange= function() {
        wm.weathermap.resSlider.setValue(parseInt(this.value));
    };
    var resTicks = document.getElementById("resTicks");
    initNumericTicks(resTicks, 168, 1, 30);
}

function initAggregationSlider() {
    wm.weathermap.aggrSlider.setMinimum(1);
    wm.weathermap.aggrSlider.setMaximum(168);
    wm.weathermap.aggrSlider.mouseUpHandler = aggrSliderMouseUp;
    wm.weathermap.aggrSlider.onchange = function () {
	      document.getElementById("aggrValue").value =
           wm.weathermap.aggrSlider.getValue() / 2;
    };
    var aggrValue = document.getElementById("aggrValue");
    aggrValue.value = 0.5;
    aggrValue.onchange= function() {
        wm.weathermap.aggrSlider.setValue(parseInt(this.value)/2);
    };
    var aggrTicks = document.getElementById("aggrTicks");
    initNumericTicks(aggrTicks, 168, 0.5, 84);
}

function initNumericTicks(tickDiv, width, first, last) {
    tickDiv.style.width = width + 22; 
    // tick image is 6 pixels in width, 42 should be big enough to handle
    // four-digit numbers
    var numTicks = width / 42;
    var tickInterval = (last - first) / numTicks;
    // create start element
    var newdiv = document.createElement("div");
    // setting float property doesn't work in FF
    newdiv.className = "tick";
    newdiv.style.width = "42px";
    newdiv.innerHTML = first;
    tickDiv.appendChild(newdiv);
    for (var i = 1; i < numTicks; i++) {
        newdiv = document.createElement("div");
        newdiv.className = "tick";
        newdiv.style.width = "42px";
        var label = Math.round(first + i * tickInterval);
        newdiv.innerHTML = label + "";
        tickDiv.appendChild(newdiv);
    }
    // create end element
    newdiv = document.createElement("div");
    newdiv.className = "tick";
    newdiv.style.width = "15px";
    newdiv.innerHTML = last;
    tickDiv.appendChild(newdiv);
}

function resetSlider(startSeconds, endSeconds) {
    var interval = endSeconds - startSeconds;
    var nextPeriod;
    if (interval <= 3600) {
        nextPeriod = "seconds";
    } else if (interval <= 86400) {
       nextPeriod = "minutes";
    } else if (interval <= 604800) {
        nextPeriod = "hours";
    } else {
        nextPeriod = "days";
    }
    if (wm.weathermap.currentPeriod != nextPeriod) {
        wm.weathermap.currentPeriod = nextPeriod;
        var res = document.getElementById("resolution");
        res.innerHTML = nextPeriod;
        var resValue = document.getElementById("resValue");
        var start = wm.weathermap.resPeriods[nextPeriod].start;
        var end = wm.weathermap.resPeriods[nextPeriod].end;
        wm.weathermap.resSlider.setMinimum(start);
        wm.weathermap.resSlider.setMaximum(end);
        var resTicks = document.getElementById("resTicks");
        resetNumericTicks(resTicks, 168, start, end);
    }
}

function resetNumericTicks(tickDiv, width, first, last) {
    var numTicks = width / 42;
    var tickInterval = (last - first) / numTicks;
    var children = tickDiv.childNodes;
    children[1].innerHTML = first;
    for (var i=2; i < children.length-1; i++) {
        var label = Math.round(first + (i-1) * tickInterval);
        children[i].innerHTML = label + "";
    }
    children[children.length-1].innerHTML = last;
}

// end of common material

/**
 * Calls the draw functon for level 0 or level 1 based on the current zoom level
 * newLevel - level of zoom
 */
function determineLevelBasedOnZoom(newLevel) {
    console.log("determineLevelBasedOnZoom level " + newLevel);
    var changed = false;
    if (wm.weathermap.auto == 1) {
        if (newLevel < 9 && wm.weathermap.lod != 0) {
            changed = true;
            wm.weathermap.lod = 0;
        } else if(newLevel >= 9 && wm.weathermap.lod != 1){
            changed = true;
            wm.weathermap.lod = 1;
        }
    }
    // see http://www.javascriptkit.com/javatutors/objdetect3.shtml
    // don't change every time if Firefox
    if (changed || !(window.globalStorage && window.postMessage)) {
        GEvent.trigger(wm.weathermap.eventDummy, "lodChanged");
    }
}

function getAutoVal() {
    return wm.weathermap.auto;
}

/////////////////////////////////////////////////////////////////////////////////
// List box (dropdown) call back functions
/////////////////////////////////////////////////////////////////////////////////

/**
 * Function that detects the user's selection in the drop down menu
 * and calls appropriate function.
 */
function dropdown() {
    var w = document.getElementById("form").lod.selectedIndex;
    var value = document.getElementById("form").lod.options[w].value;
    var prevLod = wm.weathermap.lod;
    if (value == "auto"){
        wm.weathermap.auto = 1;
        // FIXME:  not sure how this worked before
        if (!wm.weathermap.flash) {
            determineLevelBasedOnZoom(wm.renderer.map.getZoom());
        }
    } else {
        wm.weathermap.auto = 0;
        wm.weathermap.lod = value;
        if (wm.weathermap.lod != prevLod) {
            GEvent.trigger(wm.weathermap.eventDummy, "lodChanged");
        }
    }
}

function metricSelection() {
    var w = document.getElementById("form").metricsDD.selectedIndex;
    var value = document.getElementById("form").metricsDD.options[w].value;
    console.log("metricSelection: " + value);
    wm.weathermap.metricChoice=value;
    // if percent utilized, average and max don't mean anything, just capacity
    if (value == 1) {
        document.getElementById("form").metricsType.disabled = true;
    } else {
        document.getElementById("form").metricsType.disabled = false;
    }
    GEvent.trigger(wm.weathermap.eventDummy, "showMetric");
}

function metricTypeSelection() {
    var w = document.getElementById("form").metricsType.selectedIndex;
    var value = document.getElementById("form").metricsType.options[w].value;
    console.log("metricTypeSelection: " + value);
    wm.weathermap.metricTypeChoice=value;
    GEvent.trigger(wm.weathermap.eventDummy, "showMetric");
}

function circuitSelection() {
    var w = document.getElementById("form").circuitDD.selectedIndex;
    wm.weathermap.pathChoice =
        document.getElementById("form").circuitDD.options[w].value;
    GEvent.trigger(wm.weathermap.eventDummy, "showPath");
}

function updateOscarsForm() {

    var sortedPath = getSortedPath();
    for (var x in sortedPath) {
        var optn = document.createElement("option");
        var selectbox = document.getElementById("form").circuitDD;
        optn.text = "---"+x+"---";
        optn.value = "undef";
        selectbox.options.add(optn);

        var numericSortArray = new Array();
        for (var j=0; j < sortedPath[x].length; j++) {
            numericSortArray.push(sortedPath[x][j]);
        }
        numericSortArray.sort(resvOrd);
        for (var i=0; i<sortedPath[x].length; i++) {
            var optn1 = document.createElement("option");
            var selectbox1 = document.getElementById("form").circuitDD;
            optn1.text = numericSortArray[i];
            optn1.value = numericSortArray[i];
            selectbox1.options.add(optn1);
        }
    }
}

//sorted according to source
 function getSortedPath() {
    var sPath = new Object();
    var tmp = new Array();
    var count = 0;
    for (var pName in wm.path.pathsData) {
         if (count == 0) {
             tmp[count] = wm.path.pathsData[pName].group;
             count++;
         } else {
             if (wm.path.pathsData[pName].group != tmp[count]) {
                 tmp[count] = wm.path.pathsData[pName].group;
                 count++;
             }
         }
    }
    tmp.sort();
    for (var i=0; i<tmp.length; i++) {
        var tmpArray = new Array();
        for (var pName in wm.path.pathsData) {
            if(wm.path.pathsData[pName].group == tmp[i]) {
                tmpArray.push(wm.path.pathsData[pName].id);
            }
        }
        sPath[tmp[i]] = tmpArray;
    }
    return sPath;
}

function resvOrd(a, b) {
    var tmpa = a.split("-");
    var tmpb = b.split("-");
    return tmpa[1] - tmpb[1];
}

/////////////////////////////////////////////////////////////////////////////////
// Checkbox call back functions
/////////////////////////////////////////////////////////////////////////////////
/**
 * Function that toggles the labels on and off based on user's selection.
 * Default is on.
 */
function toggleLabels() {
    var showLabels = document.getElementById("labelsCheckbox").checked;
    labelVisibility(showLabels);
}

function toggleSdn() {
    wm.weathermap.showSdn = document.getElementById("sdnCheckbox").checked;
    // a fix for flash bug, but it will cause confusion for the user if
    // labels not really checked
    document.getElementById("labelsCheckbox").checked = true;
    document.getElementById("peersOnlyCheckbox").checked = false;
    wm.weathermap.peersOnly = false;
    GEvent.trigger(wm.weathermap.eventDummy, "topologyChanged");
}

function toggleIp() {
     //a fix for flash bug
    document.getElementById("labelsCheckbox").checked = true;
    wm.weathermap.showIp = document.getElementById("ipCheckbox").checked;
    document.getElementById("peersOnlyCheckbox").checked = false;
    wm.weathermap.peersOnly = false;
    GEvent.trigger(wm.weathermap.eventDummy, "topologyChanged");
}

function toggleSites() {
     //a fix for flash bug
    document.getElementById("labelsCheckbox").checked = true;
    wm.weathermap.showSites = document.getElementById("sitesCheckbox").checked;
    document.getElementById("peersOnlyCheckbox").checked = false;
    wm.weathermap.peersOnly = false;
    GEvent.trigger(wm.weathermap.eventDummy, "topologyChanged");
}

function togglePeers() {
     //a fix for flash bug
    document.getElementById("labelsCheckbox").checked = true;
    wm.weathermap.showPeers = document.getElementById("peersCheckbox").checked;
    if (!wm.weathermap.showPeers) {
        document.getElementById("peersOnlyCheckbox").checked = false;
        wm.weathermap.peersOnly = false;
    }
    GEvent.trigger(wm.weathermap.eventDummy, "topologyChanged");
}

function togglePeersOnly(init) {
    document.getElementById("labelsCheckbox").checked = true;
    wm.weathermap.peersOnly = document.getElementById("peersOnlyCheckbox").checked;
    if (wm.weathermap.peersOnly || init) {
        wm.weathermap.saveShowIp = wm.weathermap.showIp;
        wm.weathermap.saveShowSdn = wm.weathermap.showSdn;
        wm.weathermap.saveShowSites = wm.weathermap.showSites;
        wm.weathermap.saveShowPeers = wm.weathermap.showPeers;
        wm.weathermap.showSdn = false;
        wm.weathermap.showIp = false;
        wm.weathermap.showSites = false;
        wm.weathermap.showPeers = true;
        document.getElementById("ipCheckbox").checked = false;
        document.getElementById("sdnCheckbox").checked = false;
        document.getElementById("sitesCheckbox").checked = false;
        document.getElementById("peersCheckbox").checked = true;
        if (init) {
            document.getElementById("peersOnlyCheckbox").checked = true;
            wm.weathermap.peersOnly = true;
        }
    } else {
        wm.weathermap.showIp = wm.weathermap.saveShowIp;
        wm.weathermap.showSdn = wm.weathermap.saveShowSdn;
        wm.weathermap.showSites = wm.weathermap.saveShowSites;
        wm.weathermap.showPeers = wm.weathermap.saveShowPeers;
        document.getElementById("ipCheckbox").checked = wm.weathermap.showIp;
        document.getElementById("sdnCheckbox").checked = wm.weathermap.showSdn;
        document.getElementById("sitesCheckbox").checked = wm.weathermap.showSites;
        document.getElementById("peersCheckbox").checked = wm.weathermap.showPeers;
    }
    if (!init) {
        GEvent.trigger(wm.weathermap.eventDummy, "topologyChanged");
    }
}

function toggleLogicalView() {
    // a fix for flash bug
    document.getElementById("labelsCheckbox").checked = true;
    if (document.getElementById("lvCheckbox").checked) {
        wm.weathermap.layoutType = "circle";
        wm.weathermap.lvVal=1;
    } else {
        wm.weathermap.layoutType = "geo";
        wm.weathermap.lvVal=0;
    }
    getTopology(wm.weathermap.layoutType);

}

function getLogVal() {
    return wm.weathermap.lvVal;
}

function chooseUtilizationLegend() {
    var newdiv = document.getElementById('keyMbpsdiv');
    var olddiv = document.getElementById('keyUtildiv');
    if (wm.weathermap.metricChoice == 2) {
        console.log("legend choice: " + wm.weathermap.metricChoice);
        olddiv.style.display='none';
        newdiv.style.display='block';
    } else {
        olddiv.style.display='block';
        newdiv.style.display='none';
    }

}

function toggleFullScreen(demo) {
    var hdrdiv = document.getElementById("header");
    var ftrdiv = document.getElementById("footer");
    var bardiv = document.getElementById("sidebar");
    var toggle = document.getElementById("sidebarViewToggle");
    var mapdiv = document.getElementById("map_canvas");
    if (toggle.className == "min") {
        hdrdiv.style.display='none';
        ftrdiv.style.display='none';
        bardiv.style.display='none';
        if (!demo) {
            toggle.className = "max";
            toggle.title = "Show sidebar";
            mapdiv.style.width='100%';
            mapdiv.style.height='95%';
        } else {
            toggle.style.display = "none";
            mapdiv.style.width='100%';
            mapdiv.style.height='100%';
        }
    } else {
        hdrdiv.style.display='block';
        ftrdiv.style.display='block';
        bardiv.style.display='block';
        toggle.className = "min";
        toggle.title = "Hide sidebar";
        mapdiv.style.width='85%';
        mapdiv.style.height='85%';
    }
}

function toggleOptionsDiv(display) {
    var options = document.getElementById("options");
    if (!display) {
        options.style.display='none';
    } else {
        options.style.display='block';
    }
}

function toggleOptions() {
    var toggle = document.getElementById("optionToggle");
    var optList = document.getElementById("optionList");
    if (toggle.className == "tableMin") {
        optList.style.display='none';
        toggle.className = "tableMax";
        toggle.title = "Show control options";
    } else {
        optList.style.display='block';
        toggle.className = "tableMin";
        toggle.title = "Hide control options";
    }
}

function toggleUtilLegend() {
    var percentToggle = document.getElementById("percentToggle");
    var percentTable = document.getElementById("percentTable");
    var mbpsToggle = document.getElementById("mbpsToggle");
    var mbpsTable = document.getElementById("mbpsTable");
    // both will be the same
    if (percentToggle.className == "tableMin") {
        percentTable.style.display='none';
        mbpsTable.style.display='none';
        percentToggle.className = "tableMax";
        percentToggle.title = "Show utilization legend";
        mbpsToggle.className = "tableMin";
        mbpsToggle.title = "Show utilization legend";
    } else {
        percentTable.style.display='block';
        mbpsTable.style.display='block';
        percentToggle.className = "tableMin";
        percentToggle.title = "Hide utilization legend";
        mbpsToggle.className = "tableMax";
        mbpsToggle.title = "Hide utilization legend";
    }
}

function toggleMarkerLegend() {
    var toggle = document.getElementById("markerToggle");
    var table = document.getElementById("markers");
    if (toggle.className == "tableMin") {
        table.style.display='none';
        toggle.className = "tableMax";
        toggle.title = "Show marker legend";
    } else {
        table.style.display='block';
        toggle.className = "tableMin";
        toggle.title = "Hide marker legend";
    }
}

function togglePlayback() {
    var toggle = document.getElementById("playbackToggle");
    var form = document.getElementById("playbackForm");
    if (toggle.className == "tableMin") {
        form.style.display='none';
        toggle.className = "tableMax";
        toggle.title = "Show playback options";
    } else {
        form.style.display='block';
        toggle.className = "tableMin";
        toggle.title = "Hide playback options";
        // fix for bug
        wm.weathermap.resSlider.setValue(2);
        wm.weathermap.resSlider.setValue(1);
    }
}

function showLoadingPopup() {
    if (!document.getElementById("loadingPlaybackPopup")) {
        return;
    }
    document.getElementById("startDate").disabled = true;
    document.getElementById("playbackForm").startHour.disabled = true;
    document.getElementById("playbackForm").startHourOption.disabled = true;
    document.getElementById("endDate").disabled=true;
    document.getElementById("playbackForm").endHour.disabled=true;
    document.getElementById("playbackForm").endHourOption.disabled=true;
    document.getElementById("loadingPlaybackPopup").style.display = "block";
}

function hideLoadingPopup() {
    if (!document.getElementById("loadingPlaybackPopup")) {
        return;
    }
    document.getElementById("startDate").disabled = false;
    document.getElementById("playbackForm").startHour.disabled = false;
    document.getElementById("playbackForm").startHourOption.disabled = false;
    document.getElementById("endDate").disabled=false;
    document.getElementById("playbackForm").endHour.disabled=false;
    document.getElementById("playbackForm").endHourOption.disabled=false;
    document.getElementById("loadingPlaybackPopup").style.display = "none";
}

function playbackHistory() {
    // if was paused, start loop again
    if (wm.metrics.paused) {
        wm.metrics.paused = false;
        document.getElementById("playButton").style.backgroundColor = "#FFCC66";
        document.getElementById("stepButton").style.backgroundColor = "#FFFFFF";
        document.getElementById("pauseButton").style.backgroundColor = "#FFFFFF";
        document.getElementById("stopButton").style.backgroundColor = "#FFFFFF";
        setTimeout("runLoop()", 100);
        return;
    }
    var startDate = document.getElementById("startDate");
    var startHour = document.getElementById("playbackForm").startHour;
    var startHourOption = document.getElementById("playbackForm").startHourOption;
    var endDate = document.getElementById("endDate");
    var endHour = document.getElementById("playbackForm").endHour;
    var endHourOption = document.getElementById("playbackForm").endHourOption;
    if (isBlank(startDate.value)) {
        alert("Please enter a start date");
        return;
    }
    var dateFields = startDate.value.split("-");
    // seconds since epoch
    var startSeconds = convertToSeconds(dateFields, startHour, startHourOption);
    if (startSeconds < 0) {
        return;
    }
    if (isBlank(endDate.value)) {
        alert("Please enter an end date");
        return;
    }
    var endSeconds;
    if (endDate.value != "now") {
        dateFields = endDate.value.split("-");
        endSeconds = convertToSeconds(dateFields, endHour, endHourOption);
        if (endSeconds < 0) {
            return;
        }
    } else {
        endSeconds = new Date().getTime()/1000;
        // round to nearest hour
        var rem = endSeconds % 3600;
        endSeconds -= rem;
    }
    if (startSeconds >= endSeconds) {
        alert("Please enter an end time later than the start time");
        return;
    }
    var now = new Date().getTime()/1000;
    if (startSeconds >= now) {
        alert("Please enter a start time in the past.");
        return;
    }
    if (endSeconds >= now) {
        alert("Please enter an end time in the past.");
        return;
    }
    resetSlider(startSeconds, endSeconds);
    requestPlayback(startSeconds, endSeconds);
}

function convertToSeconds(dateFields, hourMenu, amOrPmMenu) {
    if (dateFields.length != 3) {
        alert("Please use the calendar widget to input the date");
        return -1;
    }
    var today = new Date();
    if (isNaN(dateFields[2]) || ((dateFields[2] != 2008) && (dateFields[2] != 2009))) {
        alert(dateFields[2] + " is not a valid year");
        return -1;
    } else {
        dateFields[2] *= 1;
    }
    if (isNaN(dateFields[0]) || (dateFields[0] < 1) || (dateFields[0] > 12)) {
        alert(dateFields[0] + " is not a valid month");
        return -1;
    } else {
        dateFields[0] *= 1;
        dateFields[0] -= 1;
    }
    var maxDate;
    if ((dateFields[0] == 4) || (dateFields[0] == 6) || (dateFields[0] == 9) ||
        (dateFields[0] == 11)) {
        maxDate = 30;
    } else if (dateFields[0] != 2) {
        maxDate = 31;
    } else if ((dateFields[2] % 4) != 0) {
        maxDate = 28;
    } else {
        maxDate = 29;
    }
    if (isNaN(dateFields[1]) || (dateFields[1] < 1) || (dateFields[1] > maxDate)) {
        alert(dateFields[1] + " is not a valid date for " + dateFields[0]);
        return -1;
    } else {
        dateFields[1] *= 1;
    }
    var index = hourMenu.selectedIndex;
    var hour = hourMenu.options[index].value * 1;
    index = amOrPmMenu.selectedIndex;
    if (amOrPmMenu.options[index].value == "pm") {
        if (hour != 12) {
            hour += 12;
        }
    } else if (hour == 12) {
        hour = 0;
    }
    var finalDate =
        new Date(dateFields[2], dateFields[0], dateFields[1], hour, 0, 0, 0);
    var seconds = finalDate.getTime()/1000;
    return seconds;

}

// Outputs datetime with format: 09-09-2009 9:00 am/pm, given seconds since
// epoch.
function convertFromSeconds(seconds) {
    var jsDate = new Date(seconds*1000);
    // put in format that is sortable
    var year = jsDate.getFullYear();
    var month = jsDate.getMonth() + 1;
    month = (month > 9 ? '' : '0') + month;
    var day = jsDate.getDate();
    day = (day > 9 ? '' : '0') + day;
    var hour = jsDate.getHours();
    var isAm = true;
    if (hour >= 12) {
        isAm = false;
        if (hour > 12) {
            hour -= 12;
        }
    }
    hour = (hour > 9 ? '' : '0') + hour;
    var formattedDt = month + "-" + day + "-" + year + " " + hour; 
    if (isAm) {
        formattedDt += " am";
    } else {
        formattedDt += " pm";
    }
    return formattedDt;
};

// From Javascript book, p. 264

// check to see if no parameter set
function isBlank(str) {
    if (!str) {
        return true;
    }
    for (var i = 0; i < str.length; i++) {
        var c = str.charAt(i);
        if ((c != ' ') && (c != '\n') && c) { return false; }
    }
    return true;
}

